package tests;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import simulation.AgentManager;
import simulation.Simulation;
import simulation.TrafficInfrastructureManager;
import simulation.Simulation.AgentProvider;
import agents.Agent;
import agents.resource.CrossRoadAgent;
import agents.resource.RoadAgent;
import agents.task.TaskAgent;
import domain.Car;
import domain.Clock;
import domain.Segment;
import domain.Task;
import facade.TrafficInfrastructureFacade;
import gui.MainWindow;

public class TestPerformance implements AgentProvider {

	//	indien test runnen met meerdere cars	
	public static final boolean SECOND_ITERATION = true;
	
	public static void main(String[] args) {
		TestPerformance e = new TestPerformance();
		e.runTest(true, 500);

	}

	public TestPerformance(){
		experiment = new ExperimentSetup5();
		agentManager = experiment.getAgents();
		infrastructure = experiment.getInfrastructure();
		agentManager.addAllTaskAgents(getInitialTasks());
	}
	
	public void runTest(boolean useGUI, long duration) {
		TrafficInfrastructureFacade t = new TrafficInfrastructureFacade(infrastructure);
		
		if(useGUI) {
			MainWindow mainWindow = new MainWindow(t);
			mainWindow.setVisible(true);
		}
		
		initializeTaskDurations();
		Simulation sim = new Simulation(this);
		for(int i = 0; i < duration; i++) {
			try {
				if(useGUI) Thread.sleep(700);
				sim.doSimulationStep();
			} catch (InterruptedException exc) {
				exc.printStackTrace();
			}
		}
		
		System.out.println("PERFORMANTIE: " + (performance/nbCarsMeasured));
	}
	
	public TrafficInfrastructureManager getInfrastructure(){
		return infrastructure;
	}
	
	public AgentManager getAgents(){
		return agentManager;
	}
	
	private TrafficInfrastructureManager infrastructure;
	private AgentManager agentManager;
	private ExperimentSetup experiment;
	
	private Collection<TaskAgent> getInitialTasks() {
		Collection<TaskAgent> taskAgents = new ArrayList<TaskAgent>();
		
		RoadAgent agent21 = (RoadAgent) agentManager.getResourceAgentOf("road21");
		RoadAgent agent46 = (RoadAgent) agentManager.getResourceAgentOf("road46");
		CrossRoadAgent c5 = (CrossRoadAgent) agentManager.getResourceAgentOf("c5");
		Car porshe = infrastructure.getCar("porshe");
		Task t1 = new Task(c5.getTrafficInfrastructure().getSegment(), porshe);
		TaskAgent porsheTask = new TaskAgent(t1);
		taskAgents.add(porsheTask);
		
		RoadAgent agent72 = (RoadAgent) agentManager.getResourceAgentOf("road72");
		Car pk = infrastructure.getCar("pk");
		Task t2 = new Task(agent72.getTrafficInfrastructure().getSegments().get(1), pk);
		TaskAgent pkTask = new TaskAgent(t2);
		taskAgents.add(pkTask);
		
		CrossRoadAgent c6 = (CrossRoadAgent) agentManager.getResourceAgentOf("c6");
		Car renault = infrastructure.getCar("renault");
		Task t3 = new Task(c6.getTrafficInfrastructure().getSegment(), renault);
		TaskAgent renaultTask = new TaskAgent(t3);
		taskAgents.add(renaultTask);
		
		//CrossRoadAgent agentC3 = (CrossRoadAgent) agentManager.getResourceAgentOf("c3");
		Car vw = infrastructure.getCar("vw");
		Task t4 = new Task(agent46.getTrafficInfrastructure().getSegments().get(4), vw);
		TaskAgent vwTask = new TaskAgent(t4);
		taskAgents.add(vwTask);
		
		CrossRoadAgent c8 = (CrossRoadAgent) agentManager.getResourceAgentOf("c8");
		Car volvo = infrastructure.getCar("volvo");
		Task t5 = new Task(c8.getTrafficInfrastructure().getSegment(), volvo);
		TaskAgent volvoTask = new TaskAgent(t5);
		taskAgents.add(volvoTask);
		
		RoadAgent agent86 = (RoadAgent) agentManager.getResourceAgentOf("road86");
		//CrossRoadAgent c1 = (CrossRoadAgent) agentManager.getResourceAgentOf("c1");
		Car audi = infrastructure.getCar("audi");
		Task t6 = new Task(agent86.getTrafficInfrastructure().getSegments().get(0), audi);
		TaskAgent audiTask = new TaskAgent(t6);
		taskAgents.add(audiTask);
		
		Car suzuki = infrastructure.getCar("suzuki");
		Task t7 = new Task(c6.getTrafficInfrastructure().getSegment(), suzuki);
		TaskAgent suzukiTask = new TaskAgent(t7);
		taskAgents.add(suzukiTask);
		
		
		Car ferrari = infrastructure.getCar("ferrari");
		Task t8 = new Task(agent86.getTrafficInfrastructure().getSegments().get(1), ferrari);
		TaskAgent ferrariTask = new TaskAgent(t8);
		taskAgents.add(ferrariTask);
		
		
		
		Car opel = infrastructure.getCar("opel");
		Task t9 = new Task(agent46.getTrafficInfrastructure().getSegments().get(5), opel);
		TaskAgent opelTask = new TaskAgent(t9);
		taskAgents.add(opelTask);
		
		//RoadAgent agent82 = (RoadAgent) agentManager.getResourceAgentOf("road82");
		Car ford = infrastructure.getCar("ford");
		Task t10 = new Task(agent46.getTrafficInfrastructure().getSegments().get(1), ford);
		TaskAgent fordTask = new TaskAgent(t10);
		taskAgents.add(fordTask);
		
		RoadAgent agent35 = (RoadAgent) agentManager.getResourceAgentOf("road35");
		Car spyker = infrastructure.getCar("spyker");
		Task t11 = new Task(agent35.getTrafficInfrastructure().getSegments().get(2), spyker);
		TaskAgent spykerTask = new TaskAgent(t11);
		taskAgents.add(spykerTask);
		
		//RoadAgent agent67 = (RoadAgent) agents.getResourceAgentOf("road67");
		CrossRoadAgent c3 = (CrossRoadAgent) agentManager.getResourceAgentOf("c3");
		Car mclaren = infrastructure.getCar("mclaren");
		Task t12 = new Task(c3.getTrafficInfrastructure().getSegment(), mclaren);
		TaskAgent mclarenTask = new TaskAgent(t12);
		taskAgents.add(mclarenTask);
		
		CrossRoadAgent c0 = (CrossRoadAgent) agentManager.getResourceAgentOf("c0");
		Car toyota = infrastructure.getCar("toyota");
		Task t13 = new Task(c0.getTrafficInfrastructure().getSegment(), toyota);
		TaskAgent toyTask = new TaskAgent(t13);
		taskAgents.add(toyTask);
		
		if(SECOND_ITERATION){
			
			Car peugot = infrastructure.getCar("peugot");
			Task t14 = new Task(c8.getTrafficInfrastructure().getSegment(), peugot);
			TaskAgent peugotTask = new TaskAgent(t14);
			taskAgents.add(peugotTask);
			
			Car mercedes = infrastructure.getCar("mercedes");
			Task t15 = new Task(c8.getTrafficInfrastructure().getSegment(), mercedes);
			TaskAgent merTask = new TaskAgent(t15);
			taskAgents.add(merTask);
			
			Car bentley = infrastructure.getCar("bentley");
			Task t16 = new Task(c8.getTrafficInfrastructure().getSegment(), bentley);
			TaskAgent benTask = new TaskAgent(t16);
			taskAgents.add(benTask);
			
			Car lamborgini = infrastructure.getCar("lamborgini");
			Task t17 = new Task(c8.getTrafficInfrastructure().getSegment(), lamborgini);
			TaskAgent lamTask = new TaskAgent(t17);
			taskAgents.add(lamTask);
			
			Car lada = infrastructure.getCar("lada");
			Task t18 = new Task(c8.getTrafficInfrastructure().getSegment(), lada);
			TaskAgent ladaTask = new TaskAgent(t18);
			taskAgents.add(ladaTask);
			
			Car hummer = infrastructure.getCar("hummer");
			Task t19 = new Task(c3.getTrafficInfrastructure().getSegment(), hummer);
			TaskAgent hummerTask = new TaskAgent(t19);
			taskAgents.add(hummerTask);
			
			Car bmw = infrastructure.getCar("bmw");
			Task t20 = new Task(agent46.getTrafficInfrastructure().getSegments().get(0), bmw);
			TaskAgent bmwTask = new TaskAgent(t20);
			taskAgents.add(bmwTask);
			
			Car jaguar = infrastructure.getCar("jaguar");
			Task t21 = new Task(agent46.getTrafficInfrastructure().getSegments().get(1), jaguar);
			TaskAgent jaguarTask = new TaskAgent(t21);
			taskAgents.add(jaguarTask);
			
			Car jeep = infrastructure.getCar("jeep");
			Task t22 = new Task(agent46.getTrafficInfrastructure().getSegments().get(3), jeep);
			TaskAgent jeepTask = new TaskAgent(t22);
			taskAgents.add(jeepTask);
			
			Car vanhool = infrastructure.getCar("vanhool");
			Task t23 = new Task(agent46.getTrafficInfrastructure().getSegments().get(4), vanhool);
			TaskAgent vanhoolTask = new TaskAgent(t23);
			taskAgents.add(vanhoolTask);
			
			Car delorean = infrastructure.getCar("Delorean");
			Task t24 = new Task(agent46.getTrafficInfrastructure().getSegments().get(4), delorean);
			TaskAgent deloreanTask = new TaskAgent(t24);
			taskAgents.add(deloreanTask);
			
			Car saab = infrastructure.getCar("Saab");
			Task t25 = new Task(agent21.getTrafficInfrastructure().getSegments().get(4), saab);
			TaskAgent saabTask = new TaskAgent(t25);
			taskAgents.add(saabTask);
			
			Car Subaru = infrastructure.getCar("Subaru");
			Task t26 = new Task(agent21.getTrafficInfrastructure().getSegments().get(4), Subaru);
			TaskAgent subaruTask = new TaskAgent(t26);
			taskAgents.add(subaruTask);
			
			Car seat = infrastructure.getCar("Seat");
			Task t27 = new Task(agent21.getTrafficInfrastructure().getSegments().get(4), seat);
			TaskAgent seatTask = new TaskAgent(t27);
			taskAgents.add(seatTask);
			
			Car skoda = infrastructure.getCar("Skoda");
			Task t28 = new Task(agent21.getTrafficInfrastructure().getSegments().get(4), skoda);
			TaskAgent skodaTask = new TaskAgent(t28);
			taskAgents.add(skodaTask);
			
			Car smart = infrastructure.getCar("Smart");
			Task t29 = new Task(agent21.getTrafficInfrastructure().getSegments().get(4), smart);
			TaskAgent smartTask = new TaskAgent(t29);
			taskAgents.add(smartTask);
		}
		
		return taskAgents;
	}

	public Collection<Agent> getNewAgents() {
		long currentTime = Clock.getInstance().getCurrentTime();
		
		Collection<Agent> newAgents = new ArrayList<Agent>();
		
		if(currentTime == 0) { //voeg taken in beginsituatie toe
			newAgents.addAll(agentManager.getAllAgents());
			for(TaskAgent ta : agentManager.getAllTaskAgents()){
				taskBeginTime.put(ta.toString(), currentTime); //onthoud begintijd van elke gestarte taak
			}
		} else {	//later: probeer elke voltooide taak te herstarten
			
			//haal eerst alle zopas voltooide taken op
			for(TaskAgent ta : agentManager.getAllTaskAgents()) {
				if(ta.isCompleted()) {	
					agentManager.removeTaskAgent(ta);
					completedTasks.add(ta);
					long startTime = taskBeginTime.get(ta.toString());
					//System.out.println(ta.toString() + " completed at time " + currentTime + " task began at : " + startTime);
					long taskDuration = currentTime - startTime;
					Long minTaskDuration = taskMinDuration.get(ta.toString());
					
					if(minTaskDuration == null) throw new IllegalStateException("ghost car");
					if(taskDuration < minTaskDuration) throw new IllegalStateException("het onmogelijke is gebeurd");
					
					if(taskDuration > 1.5* minTaskDuration) System.out.println("SLOW! " + ta.toString() + " completed at time " + currentTime + " task took : " + taskDuration + ", minimum time is " + minTaskDuration);
						
					performance += ((float) taskDuration / (float) minTaskDuration); //update performantiemeting
					nbCarsMeasured ++;
				}
			}
			
			//probeer dan alle voltooide taken herop te starten
			List<TaskAgent> tasksToRecycle = new ArrayList<TaskAgent>(completedTasks);
			for(TaskAgent ta : tasksToRecycle) {
				Car car = ta.getCar();
				Segment startPos = experiment.getStartPosition(car);
				if(startPos.getCar() == null) { //startpositie van auto is vrij --> start auto terug op
					completedTasks.remove(ta);
					TaskAgent newTask = new TaskAgent(ta.getTask());
					car.move(startPos);
					newAgents.add(newTask);
					agentManager.addTaskAgent(newTask);
					taskBeginTime.put(ta.toString(), currentTime);
				}
			}
		}
		
		return newAgents;
	}
	
	private List<TaskAgent> completedTasks = new ArrayList<TaskAgent>(); //lijst van complete taken, die terug heropgestart dienen te worden
	
	private double performance = 0;
	private int nbCarsMeasured = 0;
	
	private void initializeTaskDurations() {
		taskMinDuration.put("volvo",37L);
		taskMinDuration.put("audi",37L);
		taskMinDuration.put("pk",33l);
		taskMinDuration.put("renault",22l);
		taskMinDuration.put("vw",17l);
		taskMinDuration.put("ferrari",34l);
		taskMinDuration.put("suzuki",19l);
		taskMinDuration.put("opel",24l);
		taskMinDuration.put("ford",19l);
		taskMinDuration.put("spyker",23l);
		taskMinDuration.put("mclaren",19l);
		taskMinDuration.put("toyota",14l);
		taskMinDuration.put("porshe",23l);
		if(SECOND_ITERATION) {
			taskMinDuration.put("peugot",35l);
			taskMinDuration.put("mercedes",34l);
			taskMinDuration.put("bentley",33l);
			taskMinDuration.put("lamborgini",32l);
			taskMinDuration.put("lada",31l);
			taskMinDuration.put("hummer",29l);
			taskMinDuration.put("bmw",25l);
			taskMinDuration.put("jaguar",25l);
			taskMinDuration.put("jeep",26l);
			taskMinDuration.put("vanhool",26l);
			taskMinDuration.put("Delorean",25l);
			taskMinDuration.put("Saab",47l);
			taskMinDuration.put("Smart",46l);
			taskMinDuration.put("Seat",45l);
			taskMinDuration.put("Subaru",44l);
			taskMinDuration.put("Skoda",43l);
		}
	}
	
	private Map<String, Long> taskBeginTime = new TreeMap<String, Long>();
	private Map<String, Long> taskMinDuration = new TreeMap<String, Long>();

	public Collection<Agent> getAgentsToRemove() {
		return new ArrayList<Agent>();
	}
}


